/**
 * @file      : user_list.c
 * @brief     : 用户链表源文件
 * @author    : huenrong (huenrong1028@gmail.com)
 * @date      : 2021-04-09 15:48:13
 *
 * @copyright : Copyright (c) 2021 胡恩荣
 *
 */

#include "./user_list.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

// 用户链表头
static struct user_list_head g_user_list_head;

// 用户链表互斥锁
static pthread_mutex_t g_user_list_mutex;

/**
 * @brief  用户链表初始化
 */
void user_list_init(void)
{
    // 初始化链表
    INIT_LIST_HEAD(&g_user_list_head.list);

    g_user_list_head.len = 0;

    // 初始化互斥锁
    pthread_mutex_init(&g_user_list_mutex, NULL);
}

/**
 * @brief  用户链表插入数据(头插法)
 * @param  add_data: 输入参数, 待插入的数据
 * @return 成功: 0
 *         失败: -1
 */
int user_list_add(const struct user_list_node_data add_data)
{
    struct user_list_node *add_node;

    add_node = (struct user_list_node *)malloc(sizeof(struct user_list_node));
    if (NULL == add_node)
    {
        return -1;
    }

    memcpy(&add_node->node_data, &add_data,
           sizeof(struct user_list_node_data));

    pthread_mutex_lock(&g_user_list_mutex);

    list_add(&add_node->list, &g_user_list_head.list);

    // 插入节点时, 链表长度增加
    g_user_list_head.len++;

    pthread_mutex_unlock(&g_user_list_mutex);

    return 0;
}

/**
 * @brief  用户链表插入数据(尾插法)
 * @param  add_data: 输入参数, 待插入的数据
 * @return 成功: 0
 *         失败: -1
 */
int user_list_add_tail(const struct user_list_node_data add_data)
{
    struct user_list_node *add_node;

    add_node = (struct user_list_node *)malloc(sizeof(struct user_list_node));
    if (NULL == add_node)
    {
        return -1;
    }

    memcpy(&add_node->node_data, &add_data,
           sizeof(struct user_list_node_data));

    pthread_mutex_lock(&g_user_list_mutex);

    list_add_tail(&add_node->list, &g_user_list_head.list);

    // 插入节点时, 链表长度增加
    g_user_list_head.len++;

    pthread_mutex_unlock(&g_user_list_mutex);

    return 0;
}

/**
 * @brief  遍历链表
 */
void user_list_for_each_entry_safe_function(void)
{
    // 临时变量
    struct user_list_node *temp;
    // 遍历得到的数据
    struct user_list_node *pos;

    pthread_mutex_lock(&g_user_list_mutex);

    list_for_each_entry_safe(pos, temp, &g_user_list_head.list, list)
    {
        printf("user list data, name: [%s], age = %d\n",
               pos->node_data.name, pos->node_data.age);
    }

    pthread_mutex_unlock(&g_user_list_mutex);
}

/**
 * @brief  用户链表删除节点(删除所有符合要求的节点)
 * @param  del_data: 输入参数, 待删除的节点数据
 */
void user_list_del(const struct user_list_node_data del_data)
{
    int ret = -1;
    // 临时变量
    struct user_list_node *temp;
    // 遍历得到的数据
    struct user_list_node *pos;

    pthread_mutex_lock(&g_user_list_mutex);

    list_for_each_entry_safe(pos, temp, &g_user_list_head.list, list)
    {
        ret = memcmp(&del_data, &pos->node_data,
                     sizeof(struct user_list_node_data));

        if (0 == ret)
        {
            list_del(&pos->list);

            // 释放节点空间
            free(pos);
            pos = NULL;

            // 删除节点时, 链表长度减小
            g_user_list_head.len > 0 ? g_user_list_head.len-- : 0;
        }
    }

    pthread_mutex_unlock(&g_user_list_mutex);
}

/**
 * @brief  用户链表删除所有节点(不包括头节点)
 */
void user_list_del_all(void)
{
    // 临时变量
    struct user_list_node *temp;
    // 遍历得到的数据
    struct user_list_node *pos;

    pthread_mutex_lock(&g_user_list_mutex);

    list_for_each_entry_safe(pos, temp, &g_user_list_head.list, list)
    {
        list_del(&pos->list);

        // 释放节点空间
        free(pos);
        pos = NULL;

        // 删除节点时, 链表长度减小
        g_user_list_head.len > 0 ? g_user_list_head.len-- : 0;
    }

    pthread_mutex_unlock(&g_user_list_mutex);
}

/**
 * @brief  判断用户链表是否为空
 * @return 0: 链表非空
 *         1: 链表为空
 */
int user_list_empty(void)
{
    int ret = -1;

    pthread_mutex_lock(&g_user_list_mutex);

    ret = list_empty(&g_user_list_head.list);

    pthread_mutex_unlock(&g_user_list_mutex);

    return ret;
}

/**
 * @brief  获取用户链表长度
 * @return 链表长度
 */
uint32_t get_user_list_len(void)
{
    return g_user_list_head.len;
}

/**
 * @brief  用户链表查找是否存在指定姓名信息
 * @param  terminal_id: 输入参数, 带查找设备
 * @return 0: 不存在
 *         1: 存在
 */
int user_list_find(const char *name)
{
    int ret = -1;
    // 临时变量
    struct user_list_node *temp;
    // 遍历得到的数据
    struct user_list_node *pos;
    // 查找标志(0: 不存在, 1: 存在)
    uint8_t find_flag = 0;

    pthread_mutex_lock(&g_user_list_mutex);

    list_for_each_entry_safe(pos, temp, &g_user_list_head.list, list)
    {
        // 存在指定设备
        ret = memcmp(name, pos->node_data.name, strlen(name));
        if (0 == ret)
        {
            find_flag = 1;
        }
    }

    pthread_mutex_unlock(&g_user_list_mutex);

    return find_flag;
}

/**
 * @brief  用户链表获取指定姓名对应的节点信息
 * @param  info: 输出参数, 获取到的节点信息
 * @param  name: 输入参数, 待获取信息的姓名
 * @return 成功: 0
 *         失败: -1
 */
int user_list_get_one_info(struct user_list_node_data *info,
                           const char *name)
{
    int ret = -1;
    // 临时变量
    struct user_list_node *temp;
    // 遍历得到的数据
    struct user_list_node *pos;

    pthread_mutex_lock(&g_user_list_mutex);

    list_for_each_entry_safe(pos, temp, &g_user_list_head.list, list)
    {
        ret = memcmp(name, pos->node_data.name, strlen(name));
        if (0 == ret)
        {
            memcpy(info, &pos->node_data, sizeof(struct user_list_node_data));
        }
    }

    pthread_mutex_unlock(&g_user_list_mutex);

    return 0;
}

/**
 * @brief  用户链表更新数据(不存在该节点, 则将数据插入链表)
 * @param  node_data: 输入参数, 待更新/插入的节点数据
 * @return 成功: 0
 *         失败: -1
 */
int user_list_update(const struct user_list_node_data node_data)
{
    int ret = -1;
    // 临时变量
    struct user_list_node *temp;
    // 遍历得到的数据
    struct user_list_node *pos;
    // 查找标志(0: 不存在, 1: 存在)
    uint8_t find_flag = 0;

    pthread_mutex_lock(&g_user_list_mutex);

    list_for_each_entry_safe(pos, temp, &g_user_list_head.list, list)
    {
        // 存在指定设备
        ret = memcmp(node_data.name, pos->node_data.name, strlen(node_data.name));
        if (0 == ret)
        {
            find_flag = 1;

            // 更新数据
            memcpy(pos->node_data.name, &node_data,
                   sizeof(struct user_list_node_data));
        }
    }

    pthread_mutex_unlock(&g_user_list_mutex);

    // 不存在节点, 则插入
    if (0 == find_flag)
    {
        ret = user_list_add_tail(node_data);

        return ret;
    }

    return 0;
}
